Author: Jorge Maldonado Ventura
Category: Desarrollo web
Date: 2017-09-02 18:30
Image: <img src="/wp-content/uploads/2017/09/menu-navegación-Bootstrap.png" alt="Ejemplo de menú de navegación de Bootstrap">
Lang: es
Modified: 2017-09-22 11:41
Slug: barra-de-navegacion-de-bootstrap-sin-javascript
Tags: Bootstrap, CSS, HTML, JavaScript, consejos, jQuery
Title: Barra de navegación de Bootstrap sin JavaScript

[Bootstrap](https://github.com/twbs/bootstrap) se distribuye con un
archivo JavaScript llamado `bootstrap.js` que requiere
[jQuery](https://es.wikipedia.org/wiki/JQuery). Este archivo permite,
entre otras cosas, hacer funcionar la barra de navegación cuando hay
menús desplegables, y desplegar y ocultar los enlaces de navegación, que
se encuentran ocultos en pantallas con baja resolución.

El problema es que Bootstrap no ofrece la misma funcionalidad básica sin
JavaScript. Es decir, si no tienes JavaScript activado, no puedes
acceder a los menús desplegables ni ocultar y mostrar el menú de
navegación en dispositivos móviles o con baja resolución. Sin embargo,
es posible ofrecer esta funcionalidad sin JavaScript. En este artículo
os muestro cómo hacerlo.

<!-- more -->

Para empezar vamos a crear un menú de navegación que funciona con
JavaScript. Recuerda asegurarte de que la ruta de los archivos
JavaScript y <abbr title="Cascading Style Sheets">CSS</abbr> es
correcta; puedes descargarlos y guardarlos en las carpetas `css` y `js`
en el mismo directorio donde se encuentra el archivo <abbr
title="HyperText Markup Language">HTML</abbr>. La versión de Bootstrap
utilizada es la 3.3.7.

    ::html
    <!DOCTYPE html>
    <html lang="es">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Con JavaScript | Barra de navegación de Bootstrap</title>
        <link rel="stylesheet" href="css/bootstrap.css" type="text/css">
        <script src="/theme/js/jquery-3.1.1.min.js"></script>
        <script src="js/bootstrap.js"></script>
      </head>
      <body>
        <nav class="navbar navbar-default navbar-fixed-top">
          <div class="container">
            <div class="navbar-header">
              <a href="/" class="navbar-brand">Freak Spot</a>
              <button aria-expanded="false" class="navbar-toggle" type="button" data-toggle="collapse" data-target="#navbar-main">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
            </div>
            <div class="navbar-collapse collapse" id="navbar-main">
              <ul class="nav navbar-nav">
                <li>
                  <a href="#">Otra sección</a>
                </li>
                <li>
                  <a href="https://es.wikipedia.org/wiki/Wikipedia:Portada">Wikipedia</a>
                </li>
                <li class="dropdown">
                  <a class="dropdown-toggle" data-toggle="dropdown" href="#" id="themes">Software libre <span class="caret"></span></a>
                  <ul class="dropdown-menu" aria-labelledby="themes">
                    <li><a href="https://www.fsf.org/">FSF</a></li>
                    <li><a href="https://www.gnu.org/">GNU</a></li>
                    <li><a href="https://peers.community/">Peers Community</a></li>
                  </ul>
                </li>
              </ul>
            </div>
          </div>
        </nav>
      </body>
    </html>

Puedes [comprobar cómo funciona](/wp-content/uploads/2017/09/barra-navegacion-Bootstrap/con-javascript.html)
este ejemplo. Cuando pulsas el menú desplegable llamado «Software
libre», aparecen otras opciones debajo; cuando la resolución es pequeña,
basta con pulsar un botón para mostrar y ocultar el menú de navegación.
Pero estas dos funcionalidades no funcionan cuando JavaScript está
desactivado.

¿Para una página tan sencilla es necesario cargar jQuery y
`bootstrap.js`? No. Vamos a dejar de utilizarlos y realizar la misma
funcionalidad con <abbr title="Cascading Style Sheets">CSS</abbr>.

Los cambios que debemos realizar son los siguientes, las líneas borradas
empiezan por `-` y las nuevas por `+` (salida obtenida con la
instrucción `diff -u con-javascript.html sin-javascript.html`):

    ::diff
    --- con-javascript.html	2017-09-16 15:02:49.883637402 +0200
    +++ sin-javascript.html	2017-09-22 11:30:50.332252781 +0200
    @@ -3,21 +3,37 @@
       <head>
         <meta charset="UTF-8">
         <meta name="viewport" content="width=device-width">
    -    <title>Con JavaScript | Barra de navegación de Bootstrap</title>
    +    <title>Sin JavaScript | Barra de navegación de Bootstrap</title>
         <link rel="stylesheet" href="css/bootstrap.css" type="text/css">
    -    <script src="/theme/js/jquery-3.1.1.min.js"></script>
    -    <script src="js/bootstrap.js"></script>
    +    <style>
    +      .dropdown:hover > .dropdown-menu {
    +        display: block;
    +      }
    +
    +      label[for=navbar-toggle-cbox] {
    +        cursor: pointer;
    +      }
    +
    +      #navbar-toggle-cbox:checked ~ .collapse {
    +        display: block;
    +      }
    +
    +      #navbar-toggle-cbox {
    +        display: none
    +      }
    +    </style>
       </head>
       <body>
         <nav class="navbar navbar-default navbar-fixed-top">
           <div class="container">
    +        <input aria-controls="navbar-main" id="navbar-toggle-cbox" role="button" type="checkbox">
             <div class="navbar-header">
               <a href="/" class="navbar-brand">Freak Spot</a>
    -          <button aria-expanded="false" class="navbar-toggle" type="button" data-toggle="collapse" data-target="#navbar-main">
    +          <label class="navbar-toggle collapsed" for="navbar-toggle-cbox">
                 <span class="icon-bar"></span>
                 <span class="icon-bar"></span>
                 <span class="icon-bar"></span>
    -          </button>
    +          </label>
             </div>
             <div class="navbar-collapse collapse" id="navbar-main">
               <ul class="nav navbar-nav">

El código fuente completo se muestra a continuación.

    ::html
    <!DOCTYPE html>
    <html lang="es">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Sin JavaScript | Barra de navegación de Bootstrap</title>
        <link rel="stylesheet" href="css/bootstrap.css" type="text/css">
        <style>
          .dropdown:hover > .dropdown-menu {
            display: block;
          }

          label[for=navbar-toggle-cbox] {
            cursor: pointer;
          }

          #navbar-toggle-cbox:checked ~ .collapse {
            display: block;
          }

          #navbar-toggle-cbox {
            display: none
          }
        </style>
      </head>
      <body>
        <nav class="navbar navbar-default navbar-fixed-top">
          <div class="container">
            <input aria-controls="navbar-main" id="navbar-toggle-cbox" role="button" type="checkbox">
            <div class="navbar-header">
              <a href="/" class="navbar-brand">Freak Spot</a>
              <label class="navbar-toggle collapsed" for="navbar-toggle-cbox">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </label>
            </div>
            <div class="navbar-collapse collapse" id="navbar-main">
              <ul class="nav navbar-nav">
                <li>
                  <a href="#">Otra sección</a>
                </li>
                <li>
                  <a href="https://es.wikipedia.org/wiki/Wikipedia:Portada">Wikipedia</a>
                </li>
                <li class="dropdown">
                  <a class="dropdown-toggle" data-toggle="dropdown" href="#" id="themes">Software libre <span class="caret"></span></a>
                  <ul class="dropdown-menu" aria-labelledby="themes">
                    <li><a href="https://www.fsf.org/">FSF</a></li>
                    <li><a href="https://www.gnu.org/">GNU</a></li>
                    <li><a href="https://peers.community/">Peers Community</a></li>
                  </ul>
                </li>
              </ul>
            </div>
          </div>
        </nav>
      </body>
    </html>

Puedes [comprobar cómo funciona](/wp-content/uploads/2017/09/barra-navegacion-Bootstrap/sin-javascript.html)
este ejemplo. Ahora no hace falta pulsar en «Software libre», sino
simplemente pasar el ratón por encima. El botón para ocultar y mostrar
los enlaces en resoluciones menores ha sido reemplazado en la versión
sin JavaScript por una casilla de verificación oculta. La casilla de
verificación se activa al pulsar el elemento `<label>` que está
asociado a esta (`for="navbar-toggle-cbox"`). Cuando la casilla está
activa, se muestran con <abbr title="Cascading Style Sheets">CSS</abbr>
(`display: block`) los enlaces del menú de navegación.

A diferencia de la versión con JavaScript, la versión sin JavaScript no
cuenta con una animación cuando se oculta o se muestra el menú de
navegación. Es imposible hacer cambiar de valor el atributo
`aria-expanded` (el cual debería cambiar a `true` cuando el menú está
desplegado), así que se debe eliminar. Además, puede que para
dispositivos móviles no sea suficiente usar el pseudoelemento `:hover`.
Lo más recomendable, en mi opinión, es evitar usar un menú desplegable
en la barra de navegación.

En conclusión, si estamos usando otras funcionalidades que ofrece el
archivo `bootstrap.js` o no queremos perder funcionalidad, no tiene
sentido eliminarlo.

Lo que se debe hacer para que le funcione bien a todo el mundo[^1]
es incluir el código que añadimos en la versión sin JavaScript dentro
de la etiqueta `<noscript>` para que la página web les funcione tanto a
quienes activan JavaScript como a quienes no. Para ocultar el botón que
se necesita en la versión con JavaScript cuando JavaScript esté
desactivado se puede asignar un `id` al botón y darle el valor `display:
none`. La solución la reproduzco a continuación.

    ::html
    <!DOCTYPE html>
    <html lang="es">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Con JavaScript y sin JavaScript | Barra de navegación de Bootstrap</title>
        <link rel="stylesheet" href="css/bootstrap.css" type="text/css">
        <script src="/theme/js/jquery-3.1.1.min.js"></script>
        <script src="js/bootstrap.js"></script>
        <style>
          #navbar-toggle-cbox {
            display: none;
          }
        </style>
        <noscript>
          <style>
            .dropdown:hover > .dropdown-menu {
              display: block;
            }

            label[for=navbar-toggle-cbox] {
              cursor: pointer;
            }

            #navbar-toggle-cbox:checked ~ .collapse {
              display: block;
            }

            #toggle-navbar {
              display: none;
            }
          </style>
        </noscript>
      </head>
      <body>
        <nav class="navbar navbar-default navbar-fixed-top">
          <div class="container">
            <input aria-controls="navbar-main" id="navbar-toggle-cbox" role="button" type="checkbox">
            <div class="navbar-header">
              <a href="/" class="navbar-brand">Freak Spot</a>
              <noscript>
                <label class="navbar-toggle" for="navbar-toggle-cbox">
                  <span class="icon-bar"></span>
                  <span class="icon-bar"></span>
                  <span class="icon-bar"></span>
                </label>
              </noscript>
              <button aria-expanded="false" class="navbar-toggle" id="toggle-navbar" type="button" data-toggle="collapse" data-target="#navbar-main">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
            </div>
            <div class="navbar-collapse collapse" id="navbar-main">
              <ul class="nav navbar-nav">
                <li>
                  <a href="#">Otra sección</a>
                </li>
                <li>
                  <a href="https://es.wikipedia.org/wiki/Wikipedia:Portada">Wikipedia</a>
                </li>
                <li class="dropdown">
                  <a class="dropdown-toggle" data-toggle="dropdown" href="#" id="themes">Software libre <span class="caret"></span></a>
                  <ul class="dropdown-menu" aria-labelledby="themes">
                    <li><a href="https://www.fsf.org/">FSF</a></li>
                    <li><a href="https://www.gnu.org/">GNU</a></li>
                    <li><a href="https://peers.community/">Peers Community</a></li>
                  </ul>
                </li>
              </ul>
            </div>
          </div>
        </nav>
      </body>
    </html>

Puedes [comprobar cómo funciona](/wp-content/uploads/2017/09/barra-navegacion-Bootstrap/con-y-sin-js.html)
este ejemplo. Las diferencias entre la versión con JavaScript y esta
solución son las siguientes:

    ::diff
    --- con-javascript.html	2017-09-16 15:02:49.883637402 +0200
    +++ con-y-sin-js.html	2017-09-22 11:31:18.527150186 +0200
    @@ -3,17 +3,49 @@
       <head>
         <meta charset="UTF-8">
         <meta name="viewport" content="width=device-width">
    -    <title>Con JavaScript | Barra de navegación de Bootstrap</title>
    +    <title>Con JavaScript y sin JavaScript | Barra de navegación de Bootstrap</title>
         <link rel="stylesheet" href="css/bootstrap.css" type="text/css">
         <script src="/theme/js/jquery-3.1.1.min.js"></script>
         <script src="js/bootstrap.js"></script>
    +    <style>
    +      #navbar-toggle-cbox {
    +        display: none;
    +      }
    +    </style>
    +    <noscript>
    +      <style>
    +        .dropdown:hover > .dropdown-menu {
    +          display: block;
    +        }
    +
    +        label[for=navbar-toggle-cbox] {
    +          cursor: pointer;
    +        }
    +
    +        #navbar-toggle-cbox:checked ~ .collapse {
    +          display: block;
    +        }
    +
    +        #toggle-navbar {
    +          display: none;
    +        }
    +      </style>
    +    </noscript>
       </head>
       <body>
         <nav class="navbar navbar-default navbar-fixed-top">
           <div class="container">
    +        <input aria-controls="navbar-main" id="navbar-toggle-cbox" role="button" type="checkbox">
             <div class="navbar-header">
               <a href="/" class="navbar-brand">Freak Spot</a>
    -          <button aria-expanded="false" class="navbar-toggle" type="button" data-toggle="collapse" data-target="#navbar-main">
    +          <noscript>
    +            <label class="navbar-toggle" for="navbar-toggle-cbox">
    +              <span class="icon-bar"></span>
    +              <span class="icon-bar"></span>
    +              <span class="icon-bar"></span>
    +            </label>
    +          </noscript>
    +          <button aria-expanded="false" class="navbar-toggle" id="toggle-navbar" type="button" data-toggle="collapse" data-target="#navbar-main">
                 <span class="icon-bar"></span>
                 <span class="icon-bar"></span>
                 <span class="icon-bar"></span>

[^1]:
    Obviamente quienes desactiven JavaScript tendrán algo menos de
    funcionalidad, pero la página será usable.
